/**********************************************************************************
 *
 *	文件名称：LinkNode.c
 * 	文件作用：包含所有图片链表的增改操作
 * 	文件作者：WSY
 * 	修改日期：2023.12.25
 *  	注意事项：
 *
 *	版权声明：CopyRight (c)  @cecelmx.126.com  All Right Reserved
 * ********************************************************************************/

#include "node.h"
#include "head.h"
#include "showImg.h"

/// @brief 输入一个文件路径和文件类型，即可生成并返回一个Data对象
/// @param Name 文件路径
/// @param Type 文件类型
/// @return 一个Data对象
DataType GetNewData(char *Name, char Type)
{
    DataType NewData = {0}; // 新建并初始化一个 Data 对象

    if (Name != NULL)
    {
        char tpm_num[6] = {0}; // 存储编号，最多为5位数
        int tpm_index = 0;     // tpm_num 的索引

        int name_length = strlen(Name);
        for (int i = 0; i < name_length; i++)
        {
            if (Name[i] >= '0' && Name[i] <= '9' && tpm_index < 5) // 只记录数字且不超过5位
            {
                tpm_num[tpm_index] = Name[i];
                tpm_index++;
            }
            else if (tpm_index == 5) // 超过5位直接退出循环
            {
                break;
            }
        }

        tpm_num[tpm_index] = '\0'; // 结尾添加'\0'，以便于atoi函数的正确使用
        int num = atoi(tpm_num);   // 将字符串里的数字转换成 int 类型

        if (num > 0) // 如果成功取得数字
        {
            strcpy(NewData.Name, Name); // 将文件路径拷贝到 Data 里的文件名数组里面
            NewData.Type = Type;        // 将文件类型赋值到 Data 对象的 Type 里
            NewData.Num = num;          // 将提取的编号赋值给 Data 对象的 Num
        }
        else{
            strcpy(NewData.Name, Name); // 将文件路径拷贝到 Data 里的文件名数组里面
            NewData.Type = Type;        // 将文件类型赋值到 Data 对象的 Type 里
            NewData.Num = -1;          // 将提取的编号赋值给 Data 对象的 Num
        }
    }
    else
    {
        printf("文件路径为空！\n");
    }

    return NewData;
}

/// @brief 传入一个Data对象地址，返回一个包函该对象的节点对象
/// @param NewData
/// @return 一个包函该对象的节点对象
P_Node NewNode(DataType *NewData)
{
    /* 申请一片空间来存放新节点 */
    P_Node New_node = calloc(1, sizeof(Node));

    /*申请的地址是空的*/
    if (New_node == NULL)
    {
        printf("内存不足，申请节点空间失败~\n");
        return NULL;
    }

    /*如果传入的不是是空对象指针*/
    if (NewData != NULL)
    {
        memcpy(&New_node->Data, NewData, sizeof(DataType));
    }

    /* 将节点指针初始话，前驱和后继都指向自己 */
    New_node->Next = New_node->Prev = New_node;

    return New_node;
}

/// @brief 将传入的左节点和待插入节点和右节点依次链接
/// @param Prev 左节点
/// @param New 待插入节点
/// @param Next 右节点
void Add2List(P_Node Prev, P_Node New, P_Node Next)
{
    Prev->Next = New;
    New->Next = Next;

    Next->Prev = New;
    New->Prev = Prev;
}

/// @brief 将传入的头结点和待插入节点有序链接
/// @param head 头结点
/// @param New 待插入节点
void Add2ListOrder(P_Node head, P_Node New)
{
    /*如果头结点比新节点的值要大，那么使用尾插，也就是将新数据放到头结点左边*/
    if (head->Data.Num > New->Data.Num)
    {
        Add2List(head->Prev, New, head);
    }

    /*定义空节点类型空指针*/
    P_Node tmp = NULL;
    for (tmp = head->Next; tmp != head &&                 // 条件1 tmp 不指向头节点
                           tmp->Data.Num <= New->Data.Num; // 条件2 tmp 的数据小于 新数据的
         tmp = tmp->Next)
        ; // tmp 往后遍历

    Add2List(tmp->Prev, New, tmp);
}

/// @brief 传入一个当前节点和一个新节点，使用尾插法将新节点插到后面一个位置
/// @param head 当前节点
/// @param New 新节点
void Add2Head(P_Node head, P_Node New)
{

    // 中心思想：先对新节点进行操作，然后再操作链表
    // 1. 让【新节点】的【后继指针】指向【第一个有效数据节点】
    New->Next = head->Next;

    // 2. 让【新节点】的【前驱指针】指向头节点
    New->Prev = head;

    // 3. 让链表的【头节点】的后继指针指向新节点
    head->Next = New;

    // 4. 让【第一个有效数据节点】的前驱指针指向新节点
    New->Next->Prev = New;

    return;
}

/// @brief 显示函数，给定一个链表头节点，遍历其所有数据并输出
/// @param head 待传入的头结点
void DisplayList(P_Node head)
{

    for (P_Node tmp = head->Next; tmp != head; tmp = tmp->Next)
    {
        printf("name: [%s] \n type: %c  num: %d\n", tmp->Data.Name, tmp->Data.Type, tmp->Data.Num);
    }
}

/// @brief 传入一个节点，将节点所有数据销毁
/// @param head
void DestroyNode(P_Node head)
{
    P_Node current = head->Next; // 从第一个有效数据节点开始
    P_Node tmp;
    while (current != head)
    {
        tmp = current->Next; // 先保存下一个节点的指针
        free(current);       // 释放当前节点的内存
        current = tmp;       // 继续处理下一个节点
    }
    head->Next = head; // 将头结点指向自己，表示链表为空
    head->Prev = head; // 同时处理头结点的 Prev 指针
    printf("节点已全部释放内存资源!\n");
}
